package config

import (
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// Conf 定义全局变量
// new()函数 获取指定类型的指针, 有点像Java中的创建对象
var Conf = new(ServConfig)

type ServConfig struct {
	Name             string `mapstructure:"name"`              // 服务名称
	Mode             string `mapstructure:"mode"`              // 环境
	Version          string `mapstructure:"version"`           // 版本
	ShutdownOvertime int    `mapstructure:"shutdown_overtime"` // 停机超时时间

	IP   string `mapstructure:"ip"`
	Port string `mapstructure:"port"`

	// 雪花算法配置
	StartTime string `mapstructure:"start_time"`
	MachineId int64  `mapstructure:"machine_id"`

	// 日志配置
	*LogConfig `mapstructure:"log"`
	// MySQL配置
	*MySQLConfig `mapstructure:"mysql"`
	// JWT 配置信息
	*JwtConfig `mapstructure:"jwt"`
}

// LogConfig 日志配置
type LogConfig struct {
	// 日志级别
	Level string `mapstructure:"level"`
	// 志文件的位置
	Filename string `mapstructure:"filename"`
	// 在进行切割之前，日志文件的最大大小（以MB为单位）
	MaxSize int `mapstructure:"max_size"`
	// 保留旧文件的最大天数
	MaxAge int `mapstructure:"max_age"`
	// 保留旧文件的最大个数
	MaxBackups int `mapstructure:"max_backups"`
}

// MySQLConfig MySQL配置信息
type MySQLConfig struct {
	Host     string `mapstructure:"host"`
	User     string `mapstructure:"user"`
	Password string `mapstructure:"password"`
	DB       string `mapstructure:"dbname"`
	Port     int    `mapstructure:"port"`
	// 最大连接数
	MaxOpenConns int `mapstructure:"max_open_conns"`
	// 最大空闲连接数
	MaxIdleConns int `mapstructure:"max_idle_conns"`
}

// JwtConfig Jwt 配置信息
type JwtConfig struct {
	SecretKey string `mapstructure:"secret_key"`
}

// Init 整个服务配置文件初始化的方法 (程序启动的时候加载配置文件)
func Init(filPath string) (err error) {
	// 直接指定配置文件路径(相对路径或者绝对路径)
	viper.SetConfigFile(filPath)

	// 读取配置文件信息
	if err = viper.ReadInConfig(); err != nil {
		return err
	}

	// 把配置文件中的信息反序列化到Conf全局变量中, 在其他地方用到配置文件中的属性的时候,可以使用全局变量中的属性
	if err = viper.Unmarshal(Conf); err != nil {
		return err
	}

	// 配置文件的监听
	viper.WatchConfig()
	// 配置文件发生变化之后,会执行下面钩子函数的监听代码
	viper.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("配置文件被修改了")
		if err := viper.Unmarshal(Conf); err != nil {
			fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
		}
	})
	return
}
